from datetime import datetime
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import models
from django.template.defaultfilters import escape
from markdown import markdown
from math import ceil

__all__ = ('ForumGroup', 'Forum', 'Post', 'ForumUser')


class ForumGroup(models.Model):
    """A group of forums."""
    title = models.CharField(max_length=200, blank=False)
    ordering = models.IntegerField(default=1)

    def __unicode__(self):
        return self.title

    class Meta:
        ordering = ('ordering', 'title', )


class Forum(models.Model):
    """A forum."""
    parent_group = models.ForeignKey(ForumGroup, related_name='forums')
    title = models.CharField(max_length=200, blank=False)
    description = models.TextField(blank=True)
    thread_count = models.IntegerField(default=0, editable=False)
    last_post = models.ForeignKey('Post', editable=False,
                                  null=True, blank=True)
    ordering = models.IntegerField(default=1)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('cp_forum', kwargs={'forum_id': self.id})

    def new_topic_url(self):
        return reverse('cp_newpost', kwargs={'forum_id': self.id})

    class Meta:
        ordering = ('parent_group', 'ordering', 'title', )


class Post(models.Model):
    """
    A forum post.

    If parent_forum is set, it's a thread start.
    If parent_post is set, it's a reply.
    """
    title = models.CharField(max_length=200, blank=True)
    title_escaped = models.CharField(max_length=250, editable=False)
    body = models.TextField(blank=False)
    body_escaped = models.TextField(editable=False)
    posted = models.DateTimeField(editable=False)

    author = models.ForeignKey('ForumUser', editable=False)
    author_ip = models.IPAddressField(help_text="Author's IP", editable=False)

    edited = models.BooleanField(default=False, editable=False)
    edited_by = models.CharField(max_length=30, blank=True, editable=False)
    edit_time = models.DateTimeField(editable=False, null=True)

    reply_count = models.IntegerField(default=0, editable=False)
    reply_num = models.IntegerField(default=0, editable=False)
    views = models.IntegerField(default=0, editable=False)

    parent_forum = models.ForeignKey(Forum, null=True, editable=False,
                                     related_name='posts')
    parent_post = models.ForeignKey('self', null=True, editable=False,
                                     related_name='replies')

    last_reply = models.ForeignKey('self', null=True, editable=False,
                                    related_name='last_reply_to')
    last_reply_time = models.DateTimeField(auto_now_add=True, editable=False)

    sticky = models.BooleanField(default=False)
    locked = models.BooleanField(default=False)

    def __unicode__(self):
        return self.title_escaped

    def thread_url(self):
        return reverse('cp_thread', kwargs={'forum_id': self.parent_forum.id,
                                            'thread_id': self.id})

    def post_url(self):
        return reverse('cp_thread',
                       kwargs={'forum_id': self.parent_post.parent_forum.id,
                               'thread_id': self.parent_post.id})

    def get_absolute_url(self):
        if self.parent_forum:
            return self.thread_url()
        else:
            page = int(ceil((self.reply_count + 1) / 40.0))
            if page == 1:
                return self.post_url()
            else:
                return "%s#p%d" % (self.post_url(), page)

    def reply_url(self):
        return reverse('cp_reply', kwargs={'forum_id': self.parent_forum.id,
                                           'thread_id': self.id})

    def edit_url(self):
        return reverse('cp_edit', kwargs={'post_id': self.id})

    def save(self):
        new_post = False
        if not self.id:
            new_post = True
            self.posted = datetime.now()
        if self.parent_post:
            self.title = "Re: %s" % self.parent_post.title
        self.title_escaped = unicode(escape(self.title))
        self.body_escaped = unicode(markdown(self.body, safe_mode=True))
        super(Post, self).save()
        if new_post:
            self.author.post_count += 1
            self.author.save()
            if self.parent_forum:
                self.parent_forum.thread_count += 1
                self.parent_forum.last_post = self
                self.parent_forum.save()
            else:
                self.reply_num = self.parent_post.reply_count + 1
                self.parent_post.reply_count += 1
                self.parent_post.last_reply = self
                self.parent_post.last_reply_time = datetime.now()
                self.parent_post.save()
                self.parent_post.parent_forum.last_post = self.parent_post
                self.parent_post.parent_forum.save()

    def delete(self):
        if self.parent_forum:
            self.parent_forum.thread_count -= 1
            if self.parent_forum.last_post == self:
                posts = self.parent_forum.posts.exclude(pk=self.id)
                posts = posts.order_by('-last_reply_time')
                if posts.count() > 0:
                    self.parent_forum.last_post = posts[0]
                else:
                    self.parent_forum.last_post = None
            self.parent_forum.save()
        else:
            self.parent_post.reply_count -= 1
            if self.parent_post.last_reply == self:
                replies = self.parent_post.posts.exclude(pk=self.id)
                replies = replies.order_by('-posted')
                if replies.count() > 0:
                    self.parent_post.last_reply = replies[0]
                else:
                    self.parent_post.last_reply = None
                self.parent_post.save()
        super(Post, self).delete()

    class Meta:
        ordering = ('posted', )


class ForumUser(models.Model):
    """A forum user."""

    ACCESS_LEVELS = (
        ('U', 'User'),
        ('M', 'Moderator'),
        ('S', 'Staff'),
    )

    nickname = models.CharField(max_length=30)
    user = models.ForeignKey(User, unique=True)
    access = models.CharField(max_length=1, choices=ACCESS_LEVELS)
    avatar = models.URLField(blank=True)
    website = models.URLField(blank=True)
    location = models.CharField(max_length=255, blank=True)
    post_count = models.IntegerField(default=0)

    def __unicode__(self):
        return self.nickname

    def get_absolute_url(self):
        return reverse('cp_userdetail', kwargs={'object_id': self.id})

    def edit_url(self):
        return reverse('cp_useredit', kwargs={'user_id': self.id})
